package com.njtoyo.taxi.admin.service.business.customer.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.OperationRecordHelper;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.rest.export.customer.CustomerArrearsExportPresenter;
import com.njtoyo.taxi.admin.rest.export.customer.CustomerPushTokenData;
import com.njtoyo.taxi.admin.rest.presenter.customer.CustomerArrearsListPresenter;
import com.njtoyo.taxi.admin.rest.presenter.customer.CustomerDetailPresenter;
import com.njtoyo.taxi.admin.rest.presenter.customer.CustomerListPresenter;
import com.njtoyo.taxi.admin.rest.presenter.customer.CustomerQueryLikeListPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.DataAuthSqlWhere;
import com.njtoyo.taxi.admin.rest.readfile.customer.CustomerPushTokenListener;
import com.njtoyo.taxi.admin.rest.readfile.customer.CustomerQueryData;
import com.njtoyo.taxi.admin.rest.readfile.customer.CustomerQueryListener;
import com.njtoyo.taxi.admin.rest.readfile.customer.CustomerQueryResult;
import com.njtoyo.taxi.admin.rest.wrapper.business.customer.*;
import com.njtoyo.taxi.admin.service.business.customer.CustomerService;
import com.njtoyo.taxi.admin.utils.AuthUtil;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.njtoyo.taxi.entity.backend.Enum;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

import static java.util.stream.Collectors.toList;

@Slf4j
@Service
@DS(Const.PRIMARY_DS)
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private CustomerInfoMapper customerInfoMapper;

    @Autowired
    private PrimaryCachePutter primaryCachePutter;

    @Autowired
    private OperationRecordHelper operationRecordHelper;

    @Autowired
    private GeoAreaMapper geoAreaMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private GeoCustomerRegionMapper customerRegionMapper;

    @Autowired
    private MemberMapper memberMapper;

    @Autowired
    private CityMapper cityMapper;

    @Autowired
    private RideOrderMapper rideOrderMapper;

    @Autowired
    private RideCancellationMapper rideCancellationMapper;
    @Autowired
    private RideMapper rideMapper;

    /**
     * 乘客列表
     *
     * @param adminUser
     * @param wrapper
     * @return
     */
    @Override
    public RestResult<Page<CustomerListPresenter>> getList(AdminUser adminUser, CustomerQueryWrapper wrapper) {
        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        if (!adminUser.getAccountType().equals(Enum.AccountType.platform)) {
            switch (adminUser.getAccountType()) {
                case company:
                case canton:
                    wrapper.setCantonIds(identity.getCantonIds());
                    break;
            }
        }
        if (Strings.isNotBlank(wrapper.getEndDate())) {
            wrapper.setEndDate(wrapper.getEndDate() + " 23:59:59");
        }
        Page<CustomerListPresenter> list = userMapper.getList(wrapper);
        List<Long> ids = list.getRecords().stream()
                .map(CustomerListPresenter::getId)
                .collect(toList());
        List<Long> cityIds = list.getRecords().stream()
                .map(CustomerListPresenter::getCityId)
                .collect(toList());
        List<Long> areaIds = list.getRecords().stream()
                .map(CustomerListPresenter::getAreaId)
                .collect(toList());
        List<Long> customerRegionIds = list.getRecords().stream()
                .map(CustomerListPresenter::getCustomerRegionId)
                .collect(toList());
        //验证是否存在数据
        if (ids.size() == 0) {
            return RestResult.success(list);
        }
        //地区信息
        QueryWrapper<GeoArea> geoAreaWrapper = new QueryWrapper<>();
        geoAreaWrapper.select("id", "name");
        geoAreaWrapper.in("id", areaIds);
        List<GeoArea> geoAreasList = geoAreaMapper.selectList(geoAreaWrapper);
        //会员信息
        QueryWrapper<Member> memberWrapper = new QueryWrapper<>();
        memberWrapper.select("id", "level", "ref_id");
        memberWrapper.eq("category", 1);
        memberWrapper.in("ref_id", ids);
        List<Member> memberList = memberMapper.selectList(memberWrapper);
        //城市信息
        QueryWrapper<City> cityQueryWrapper = new QueryWrapper<>();
        cityQueryWrapper.select("id", "name");
        cityQueryWrapper.in("id", cityIds);
        List<City> cityList = cityMapper.selectList(cityQueryWrapper);
        //乘客运营区
        QueryWrapper<GeoCustomerRegion> customerRegionQueryWrapper = new QueryWrapper<>();
        customerRegionQueryWrapper.select("id", "name");
        customerRegionQueryWrapper.in("id", customerRegionIds);
        List<Map<String, Object>> customerRegionMap =
                customerRegionMapper.selectMaps(customerRegionQueryWrapper);

        //塞值
        for (CustomerListPresenter e : list.getRecords()) {
            Long id = e.getId();
            Long cityId = e.getCityId();
            Long areaId = e.getAreaId();
            Long customerRegionId = e.getCustomerRegionId();
            //会员信息
            for (Member m : memberList) {
                if (m.getRefId().equals(id)) {
                    e.setMemberId(m.getId());
                    e.setMemberLevel(m.getLevel());
                }
            }
            //城市信息
            for (City c : cityList) {
                if (c.getId().equals(cityId)) {
                    e.setCityName(c.getName());
                }
            }
            //地区信息
            for (GeoArea g : geoAreasList) {
                if (g.getId().equals(areaId)) {
                    e.setAreaName(g.getName());
                }
            }
            //乘客运营区
            for (Map c : customerRegionMap) {
                if (c.get("id").equals(customerRegionId)) {
                    e.setCustomerRegionName(String.valueOf(c.get("name")));
                }
            }
        }
        return RestResult.success(list);
    }

    /**
     * 乘客详情
     *
     * @param id
     * @return
     */
    @Override
    public RestResult<CustomerDetailPresenter> detailsById(Long id) {
        User user = userMapper.selectById(id);
        if (ObjectUtils.isEmpty(user)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        CustomerDetailPresenter customerDetailsPresenter = new CustomerDetailPresenter();
        BeanUtils.copyProperties(user, customerDetailsPresenter);

        //会员信息
        QueryWrapper<Member> memberQueryWrapper = new QueryWrapper<>();
        memberQueryWrapper.select("id", "ref_id", "state", "level", "point", "category", "valid_point");
        memberQueryWrapper.eq("category", 1);
        memberQueryWrapper.eq("ref_id", id);
        Member member = memberMapper.selectOne(memberQueryWrapper);
        if (!ObjectUtils.isEmpty(member)) {
            customerDetailsPresenter.setMemberId(member.getId());
            customerDetailsPresenter.setLevel(member.getLevel());
            customerDetailsPresenter.setState(member.getState());
            customerDetailsPresenter.setPoint(member.getPoint());
            customerDetailsPresenter.setValidPoint(member.getValidPoint());
        }

        //账户信息
        QueryWrapper<Account> accountQueryWrapper = new QueryWrapper<>();
        accountQueryWrapper.select("amount", "default_pay_method", "pay_amount", "donation_amount");
        accountQueryWrapper.eq("customer_id", id);
        Account account = accountMapper.selectOne(accountQueryWrapper);
        if (!ObjectUtils.isEmpty(account)) {
            customerDetailsPresenter.setAmount(account.getAmount());
            customerDetailsPresenter.setDefaultPayMethod(account.getDefaultPayMethod());
            customerDetailsPresenter.setPayAmount(account.getPayAmount());
            customerDetailsPresenter.setDonationAmount(account.getDonationAmount());
        }

        //地区信息
        QueryWrapper<GeoArea> geoAreaWrapper = new QueryWrapper<>();
        geoAreaWrapper.select("id", "name");
        geoAreaWrapper.eq("id", customerDetailsPresenter.getAreaId());
        GeoArea geoArea = geoAreaMapper.selectOne(geoAreaWrapper);
        if (!ObjectUtils.isEmpty(geoArea)) {
            customerDetailsPresenter.setAreaName(geoArea.getName());
        }

        //设备信息
        QueryWrapper<CustomerInfo> customerInfoQueryWrapper = new QueryWrapper<>();
        customerInfoQueryWrapper.select("active_from", "activacated_at");
        customerInfoQueryWrapper.eq("customer_id", id);
        CustomerInfo customerInfo = customerInfoMapper.selectOne(customerInfoQueryWrapper);
        if (!ObjectUtils.isEmpty(customerInfo)) {
            customerDetailsPresenter.setActiveFrom(customerInfo.getActiveFrom());
            customerDetailsPresenter.setActivacatedAt(customerInfo.getActivacatedAt());
        }

        //乘客运营区
        QueryWrapper<GeoCustomerRegion> customerRegionQueryWrapper = new QueryWrapper<>();
        customerRegionQueryWrapper.select("id", "name");
        customerRegionQueryWrapper.eq("id", customerDetailsPresenter.getCustomerRegionId());
        GeoCustomerRegion geoCustomerRegion = customerRegionMapper.selectOne(customerRegionQueryWrapper);
        if (!ObjectUtils.isEmpty(geoCustomerRegion)) {
            customerDetailsPresenter.setCustomerRegionName(geoCustomerRegion.getName());
        }

        //激活所在时区
        QueryWrapper<GeoArea> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name");
        wrapper.eq("id", user.getAreaIdAtActivation());
        GeoArea geoAreas = geoAreaMapper.selectOne(wrapper);
        if (!ObjectUtils.isEmpty(geoAreas)) {
            customerDetailsPresenter.setAreaNameAtActivation(geoAreas.getName());
        }
        return RestResult.success(customerDetailsPresenter);
    }


    /**
     * 换手机号
     *
     * @param
     * @return
     */
    @Override
    public RestResult updateModileNumber(Long id, UpdateMobileNumberWrapper phoneWrapper) {
        User user = userMapper.selectById(id);
        if (ObjectUtils.isEmpty(user)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        String newMobileNumber = phoneWrapper.getMobileNumber();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile_number", newMobileNumber);
        Integer count = userMapper.selectCount(queryWrapper);
        if (count > 0) {
            return RestResult.failed("手机号已存在");
        }
        String oldMobileNumber = user.getMobileNumber();
        new LambdaUpdateChainWrapper<>(userMapper)
                .eq(User::getId, user.getId())
                .set(User::getMobileNumber, newMobileNumber)
                .set(User::getUpdatedAt, new Date())
                .update();
        primaryCachePutter.deleteCustomerByMobile(oldMobileNumber);
        primaryCachePutter.deleteCustomerById(user.getId());
        operationRecordHelper.addBusinessLog(String.format("将乘客 [%d] 的手机号码由 %s -> %s ", user.getId(), oldMobileNumber, newMobileNumber));
        return RestResult.success();
    }

    /**
     * 清除用户缓存
     *
     * @param id
     * @return
     */
    @Override
    public RestResult clearCache(Long id) {
        User user = userMapper.selectById(id);
        if (ObjectUtils.isEmpty(user)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        String mobileNumber = user.getMobileNumber();
        primaryCachePutter.deleteCustomerByMobile(mobileNumber);
        primaryCachePutter.deleteCustomerById(user.getId());
        primaryCachePutter.deleteCustomerWalletById(user.getId());
        operationRecordHelper.addBusinessLog(String.format("清除了乘客 [%d] 的缓存", id));
        return RestResult.success();
    }

    /**
     * 解封号
     *
     * @param id
     * @return
     */
    @Override
    public RestResult updateUnlock(Long id, UpdateUnlockWrapper updateUnlockWrapper) {
        User user = userMapper.selectById(id);
        if (ObjectUtils.isEmpty(user)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }
        new LambdaUpdateChainWrapper<>(userMapper)
                .eq(User::getId, user.getId())
                .set(User::getIsFreezed, updateUnlockWrapper.getIsFreezed())
                .set(User::getUpdatedAt, new Date())
                .update();
        primaryCachePutter.deleteCustomerByMobile(user.getMobileNumber());
        primaryCachePutter.deleteCustomerById(user.getId());
        primaryCachePutter.deleteCustomerWalletById(user.getId());
        operationRecordHelper.addBusinessLog(String.format("将乘客 [%d] 的封号状态改为%s",
                id, updateUnlockWrapper.getIsFreezed()));
        return RestResult.success();
    }

    @Override
    public RestResult<CustomerQueryResult> queryCustomerByExcel(MultipartFile file) throws IOException {
        CustomerQueryListener listener = new CustomerQueryListener(userMapper);
        EasyExcel.read(file.getInputStream(), CustomerQueryData.class, listener).sheet().doRead();
        return RestResult.success(listener.getResult());
    }

    @Override
    public void downloadPushToken(HttpServletResponse response, MultipartFile file) throws IOException {
        // 读数据
        CustomerPushTokenListener listener = new CustomerPushTokenListener(userMapper);
        EasyExcel.read(file.getInputStream(), CustomerQueryData.class, listener).sheet().doRead();

        // 写数据
        String fileName = URLEncoder.encode("乘客推送token", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), CustomerPushTokenData.class).sheet(0).doWrite(listener.getResult());
    }

    @Override
    public RestResult<Page<CustomerArrearsListPresenter>> getArrearsList(AdminUser adminUser, CustomerArrearsQueryWrapper wrapper) {
        DataAuthSqlWhere dataAuthSql = AuthUtil.getDataAuthSqlWhere();
        if(CollUtil.isNotEmpty(dataAuthSql.getCantonIds())){
            wrapper.setAreaIds(dataAuthSql.getAreaIds());
        }
        Page<CustomerArrearsListPresenter> res = null;
        switch (wrapper.getCategory()) {
            case all:
                res = this.getAllForArrearsList(wrapper);
                break;
            case ride_order:
                res = this.getRideOrderForArrearsList(wrapper);
                break;
            case ride_cancellation_order:
                res = this.getRideCancellationForArrearsList(wrapper);
                break;
        }
        if (!res.getRecords().isEmpty()) {
            for (CustomerArrearsListPresenter record : res.getRecords()) {
                Long rideId = record.getArrearsOrder().getRide().getId();
                Ride ride = rideMapper.selectById(rideId);
                record.getArrearsOrder().getRide().setRide(ride);
            }
        }

        return RestResult.success(res);
    }

    private Page<CustomerArrearsListPresenter> getRideOrderForArrearsList(CustomerArrearsQueryWrapper wrapper) {
        return rideOrderMapper.getRideOrderForArrearsList(wrapper);
    }

    private Page<CustomerArrearsListPresenter> getRideCancellationForArrearsList(CustomerArrearsQueryWrapper wrapper) {
        return rideCancellationMapper.getRideCancellationForArrearsList(wrapper);
    }

    private Page<CustomerArrearsListPresenter> getAllForArrearsList(CustomerArrearsQueryWrapper wrapper) {
        return rideOrderMapper.getAllForArrearsList(wrapper);
    }

    @Override
    public void exportArrearsList(AdminUser adminUser, CustomerArrearsExportWrapper wrapper, HttpServletResponse response) throws IOException {
        DataAuthSqlWhere dataAuthSql = AuthUtil.getDataAuthSqlWhere();
        if(CollUtil.isNotEmpty(dataAuthSql.getCantonIds())){
            wrapper.setAreaIds(dataAuthSql.getAreaIds());
        }
        List<CustomerArrearsExportPresenter> res = null;
        switch (wrapper.getCategory()) {
            case all:
                res = this.exportAllForArrearsList(wrapper);
                break;
            case ride_order:
                res = this.exportRideOrderForArrearsList(wrapper);
                break;
            case ride_cancellation_order:
                res = this.exportRideCancellationForArrearsList(wrapper);
                break;
        }

        String fileName = URLEncoder.encode("欠款乘客导出", "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), CustomerArrearsExportPresenter.class)
                .sheet(0)
                .doWrite(res);
    }

    private List<CustomerArrearsExportPresenter> exportRideOrderForArrearsList(CustomerArrearsExportWrapper wrapper) {
        return rideOrderMapper.exportRideOrderForArrearsList(wrapper);
    }

    private List<CustomerArrearsExportPresenter> exportRideCancellationForArrearsList(CustomerArrearsExportWrapper wrapper) {
        return rideCancellationMapper.exportRideCancellationForArrearsList(wrapper);
    }

    private List<CustomerArrearsExportPresenter> exportAllForArrearsList(CustomerArrearsExportWrapper wrapper) {
        return rideOrderMapper.exportAllForArrearsList(wrapper);
    }

    @Override
    public RestResult<List<CustomerQueryLikeListPresenter>> getListLike(CustomerLikeQueryWrapper wrapper) {
        // 判断是否为手机号
        List<User> list = null;
        if (this.isPhoneNum(wrapper.getSearch())) {
            list = new LambdaQueryChainWrapper<>(userMapper)
                    .select(User::getId, User::getName, User::getMobileNumber)
                    .eq(User::getMobileNumber, wrapper.getSearch())
                    .list();
        } else {
            // 先查一下
            list = new LambdaQueryChainWrapper<>(userMapper)
                    .select(User::getId, User::getName, User::getMobileNumber)
                    .eq(User::getName, wrapper.getSearch())
                    .last("limit 30")
                    .list();

            if (list.size() < 10) {
                List<User> like = new LambdaQueryChainWrapper<>(userMapper)
                        .select(User::getId, User::getName, User::getMobileNumber)
                        .ne(User::getName, wrapper.getSearch())
                        .like(User::getName, wrapper.getSearch())
                        .last(String.format("limit %d", 10 - list.size()))
                        .list();

                list.addAll(like);
            }
        }


        List<CustomerQueryLikeListPresenter> res = CopyUtil.copyList(list, CustomerQueryLikeListPresenter.class);
        return RestResult.success(res);
    }

    private Boolean isPhoneNum(String content) {
        return ReUtil.isMatch("^1[0-9]\\d{9}$", content);
    }
}
